﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using LogFileScanner.Properties;
using System.Media;
using WeifenLuo.WinFormsUI.Docking;

namespace LogFileScanner
{
    public partial class MainForm : Form
    {
        //private IDictionary<string, LogViewer> viewers = new Dictionary<string, LogViewer>();
        private AboutBox aboutBox = new AboutBox();
        private SettingsForm settingsForm = new SettingsForm();
        private ListViewColumnSorter listMatchedFilesColumnSorter = new ListViewColumnSorter();

        private HelpViewer helpViewer = new HelpViewer();
        private ScanViewer scanViewer = new ScanViewer();
        private GrepViewer grepViewer = new GrepViewer();
        private ProcessViewer processViewer = new ProcessViewer();
        private StreamList streamList = new StreamList();

        public MainForm()
        {
            InitializeComponent();
            InitializeDockedComponent();
        }

        #region UI Events
        
        private void InitializeDockedComponent() {
            addScanEvents(this.scanViewer);
            this.scanViewer.Show(dockPanel);

            addEvents(this.grepViewer);
            this.grepViewer.Show(dockPanel);

            addEvents(this.processViewer);
            processViewer.RegisterManaged(grepViewer);

            // make the scan viewer show up first
            this.scanViewer.Show(dockPanel);
        }

        private void addScanEvents(ScanViewer scanViewer)
        {
            addEvents(scanViewer);
            scanViewer.NotifyFileListLoaded += new LogFileScanner.ScanViewer.FileListLoaded(this.scanViewer_NotifyFileListLoaded);
            scanViewer.NotifyOpenGrep += new LogFileScanner.Utility.VoidMethodDelegate(this.scanViewer_NotifyOpenGrep);
            scanViewer.NotifyOpenStream += new LogFileScanner.ScanViewer.FileLoaded(this.scanViewer_NotifyOpenStream);
        }

        private void addEvents(Viewer viewer)
        {
            viewer.NotifyProgressStart += new LogFileScanner.Utility.VoidMethodDelegate(this.progressStart);
            viewer.NotifyProgressStop += new LogFileScanner.Utility.VoidMethodDelegate(this.progressStop);
            viewer.NotifyLogMessage += new LogFileScanner.Utility.MessageMethodDelegate(this.setMessage);
        }


        private StreamViewer createStreamViewer()
        {
            StreamViewer streamViewer = new StreamViewer();
            streamViewer.Command = AppSettings.StreamCommand;
            streamViewer.Arguments = AppSettings.StreamArguments;
            
            addEvents(streamViewer);
            processViewer.RegisterManaged(streamViewer);

            return streamViewer;
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                foreach (StreamViewer viewer in streamList.Streams)
                {
                    viewer.Terminate();
                    processViewer.UnregisterManaged(viewer);
                }
                streamList.Terminate();

                grepViewer.Terminate();
                processViewer.UnregisterManaged(grepViewer);

                scanViewer.Terminate();
                processViewer.Terminate();

                helpViewer.Close();
            }
            catch (Exception)
            {
                // warn here
            }
            finally
            {
                scanViewer.Close();
                grepViewer.Close();

                foreach (StreamViewer viewer in streamList.Streams)
                {
                    scanViewer.Close();
                }
            }
        }

        private void scannerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            scanViewer.Show(dockPanel);
        }

        private void grepToolStripMenuItem_Click(object sender, EventArgs e)
        {
            grepViewer.Show(dockPanel);
        }

        private void streamsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            streamList.Show(dockPanel, DockState.DockRight);
        }

        private void abourtToolStripMenuItem_Click(object sender, EventArgs e)
        {
            aboutBox.ShowDialog(this);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            settingsForm.Show(dockPanel, DockState.DockRight);
        }
        
        private void scanViewer_NotifyFileListLoaded(IList<FileInfo> files)
        {
            grepViewer.SearchScope = files;
        }

        private void scanViewer_NotifyOpenStream(FileInfo file)
        {
            StreamViewer viewer = createStreamViewer();
            viewer.FileToStream = file;
            streamList.AddStreamViewer(viewer);
            viewer.Show(dockPanel);
        }
        
        private void scanViewer_NotifyOpenGrep()
        {
            grepViewer.Show(dockPanel);
        }

        private void scanViewer_NotifyFileListLoaded()
        {
            grepViewer.Show(dockPanel);
        }

        private void processesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.processViewer.Show(dockPanel, DockState.DockRight);
        }

        private void helpToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            this.helpViewer.LoadHelp();
            this.helpViewer.Show(dockPanel);
        }

        private void checkForUpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox.CheckForUpdates();
        }

        #endregion

        #region Callbacks

        private delegate void fileInfoMethodDelegate(FileInfo file);
        private delegate Nullable<DateTime> returnDateMethodDelegate();
        private delegate string returnStringMethodDelegate();


        private void progressStart()
        {
            if (InvokeRequired) { Invoke((Utility.VoidMethodDelegate)progressStart); return; }

            progressBar.Value = 0;
            progressBar.Style = ProgressBarStyle.Marquee;
            progressBar.MarqueeAnimationSpeed = 40;
        }

        private void progressStop()
        {
            if (InvokeRequired) { Invoke((Utility.VoidMethodDelegate)progressStop); return; }

            progressBar.Value = 0;
            progressBar.Style = ProgressBarStyle.Blocks;
            progressBar.MarqueeAnimationSpeed = 0;
        }

        private void setMessage(string value, Utility.MessageLevel level)
        {
            if (InvokeRequired) { Invoke((Utility.MessageMethodDelegate)setMessage, value, level); return; }

            labelStatus.Text = value;
            switch (level)
            {
                case Utility.MessageLevel.INFO:
                    labelStatus.ForeColor = System.Drawing.SystemColors.ControlText;
                    break;
                case Utility.MessageLevel.WARN:
                    labelStatus.ForeColor = Color.Blue;

                    SystemSounds.Asterisk.Play();
                    break;
                case Utility.MessageLevel.ERROR:
                    labelStatus.ForeColor = Color.Red;

                    SystemSounds.Beep.Play();
                    break;
            }
        }

        #endregion

        #region Helper Methods

        private void OpenGrepWindow(IList<FileInfo> files)
        {
            grepViewer.SearchScope = files;
            grepViewer.Show(dockPanel);
        }

        private void OpenExternalEditor(ListViewItem listItem)
        {
            string fileName = listItem.SubItems[0].Text;
            string filePath = listItem.SubItems[1].Text;

            string commandLineArguments = string.Format(AppSettings.EditorArguments, filePath);

            try
            {
                System.Diagnostics.Process.Start(AppSettings.EditorPath, commandLineArguments);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Unable to open file {0}.\n\tUnable to start \"{1}\"\n\tWith arguments: {2}.\n\tCause: {3}",
                                fileName, AppSettings.EditorPath, commandLineArguments, ex.Message));
            }
        }

        
        #endregion


        #region Settings IO

        private Settings AppSettings
        {
            get { return Settings.Default; }
        }

        #endregion
    }
}
